package src.scheduling;

import java.io.IOException;
import java.util.ArrayList;

import src.adt.Process;
import src.adt.User;
import src.adt.Queue;

public class Multilevel {

	ArrayList<Queue> schedule;
	ArrayList<Process> allProcesses;
	ArrayList<User> allUsers;
	ArrayList<Process> remainingProcesses;
	public int clock;

	public Multilevel(ArrayList<Process> allProcesses, ArrayList<User> allUsers){

		this.allProcesses = allProcesses;
		this.allUsers = allUsers;
		this.schedule = new ArrayList<Queue>();
		clock = 0;
		remainingProcesses = new ArrayList<Process>();
		for (Process process : allProcesses)
			remainingProcesses.add(process);

		for (int i = 0; i < 4; i++)
			this.schedule.add(new Queue(allProcesses.size()));

		this.run();

	}

	public void run() {

		int totalRunTime = totalRuntTime(allProcesses);

		while (clock < totalRunTime) {

			addArrivedProcesses(clock);

			outer: for (int i = 0; i < schedule.size(); i++) {

				while (!schedule.get(i).isEmpty()) {

					int remainingQuantum = (int) Math.pow(2, i);
					Process runningProcess = null;
					while (remainingQuantum > 0 && !schedule.get(i).isEmpty()) {

						runningProcess = (Process) schedule.get(i).dequeue();
						System.out.print("At Level " + i +" and ");
						remainingQuantum = run(runningProcess, remainingQuantum);

					}

					if (remainingQuantum != 0) {

						int newLevel = i;
						if (i < 3)
							newLevel++;

						schedule.get(newLevel).enqueue(runningProcess);

					}

					addArrivedProcesses(clock);
					break outer;

				}

			}

		}

	}

	public int totalRuntTime(ArrayList<Process> allProcesses2) {

		int total = 0;

		for (Process p : allProcesses2) {
			total += p.runTime;
		}
		return (total);

	}

	public void addArrivedProcesses(int clock) {

		for (int i = 0; i < remainingProcesses.size(); i++)
			if (remainingProcesses.get(i).arrivalTime <= clock) {

				schedule.get(0).enqueue(remainingProcesses.get(i));
				remainingProcesses.remove(i);

			}

	}

	public int run(Process p, int quantum){

		int remainingQuantum = quantum - p.remainingTime;

		if (p.remainingTime < quantum) {

			this.clock += p.remainingTime;
			System.out.print("At Time " + clock + " ");
			p.run(p.remainingTime);

		} else {

			System.out.print("At Time " + clock + " ");
			p.run(quantum);
			this.clock += quantum;

		}

		return (remainingQuantum);

	}

}
